package com.boot.dog.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boot.dog.common.constant.Const;
import com.boot.dog.common.constant.SecurityConst;
import com.boot.dog.common.enums.UserType;
import com.boot.dog.common.util.*;
import com.boot.dog.entities.ao.UserAo;
import com.boot.dog.entities.base.BasePojo;
import com.boot.dog.entities.dto.UserAreaDto;
import com.boot.dog.entities.pojo.*;
import com.boot.dog.entities.vo.UserVo;
import com.boot.dog.mapper.*;
import com.boot.dog.service.UserService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author: MaxLv
 * @Date: 2020/1/9
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    @Value("${dog.server.url}")
    private String serverUrl;

    private final UserMapper userMapper;

    private final RoleMapper roleMapper;

    private final OrganizationMapper organizationMapper;

    private final UserAreaMapper userAreaMapper;

    private final UserRoleMapper userRoleMapper;

    private final AreaMapper areaMapper;

    private final PermissionMapper permissionMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> saveUser(User user, List<Integer> roleIds) {
        Integer count = userMapper.selectCount(Wrappers.<User>query().lambda().eq(User::getUsername, user.getUsername()));
        if (count > 0) {
            return Result.warn("用户名已存在");
        }
        if (StrUtil.isNotBlank(user.getAvatar())) {
            String filename = FileUtil.moveFileTempToNasFolder(user.getAvatar(), Const.USER_DIR);
            user.setAvatar(FilenameUtils.concat(Const.USER_DIR, filename));
        }
        String decodePassword = CommonUtil.getRandomChar();
        user.setPassword(new BCryptPasswordEncoder().encode(decodePassword));
        user.setDecodePassword(decodePassword);
        userMapper.insert(user);
        saveUserRole(roleIds, user);
        if (user.getOrgId() == null) {
            return Result.ok("添加用户成功");
        }
        List<Area> areas = getAreasByOrgId(user);
        user.setDataType(SecurityConst.DATA_TYPE_CUSTOM);
        userMapper.updateById(user);
        saveUserArea(areas, user);
        return Result.ok("添加用户成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> editUser(User user, List<Integer> roleIds) {
        Integer count = userMapper.selectCount(Wrappers.<User>query().lambda().eq(User::getUsername, user.getUsername()).ne(User::getId, user.getId()));
        if (count > 0) {
            return Result.warn("用户名已存在");
        }
        if (StrUtil.isNotBlank(user.getAvatar())) {
            String filename = FileUtil.moveFileTempToNasFolder(user.getAvatar(), Const.USER_DIR);
            user.setAvatar(FilenameUtils.concat(Const.USER_DIR, filename));
        }
        User oldUser = userMapper.selectById(user.getId());
        userMapper.updateById(user);
        userRoleMapper.delete(Wrappers.<UserRole>query().lambda().eq(UserRole::getUserId, user.getId()));
        saveUserRole(roleIds, user);

        if (user.getOrgId() == null || Objects.equals(user.getOrgId(), oldUser.getOrgId())) {
            return Result.ok("编辑用户成功");
        }
        List<Area> areas = getAreasByOrgId(user);
        userAreaMapper.delete(Wrappers.<UserArea>query().lambda().eq(UserArea::getUserId, user.getId()));
        saveUserArea(areas, user);
        return Result.ok("编辑用户成功");
    }

    private List<Area> getAreasByOrgId(User user) {
        Organization organization = organizationMapper.selectById(user.getOrgId());
        if (organization == null) {
            return new ArrayList<>();
        }
        return areaMapper.selectAreaByOrgPathAndLeaf(organization.getOrgPath(), SecurityConst.AREA_LEAF);
    }

    private void saveUserArea(List<Area> areas, User user) {
        List<UserArea> userAreas = areas.stream().map(area -> {
            UserArea userArea = new UserArea();
            int[] areaIds = StrUtil.splitToInt(area.getAreaPath(), "-");
            userArea.setProvinceId(areaIds[0]);
            if (areaIds.length == 2) {
                userArea.setCityId(areaIds[1]);
            }
            if (areaIds.length == 3) {
                userArea.setCityId(areaIds[1]);
                userArea.setCountyId(areaIds[2]);
            }
            if (areaIds.length == 4) {
                userArea.setCityId(areaIds[1]);
                userArea.setCountyId(areaIds[2]);
                userArea.setStreetId(areaIds[3]);
            }
            userArea.setAreaPath(area.getAreaPath());
            userArea.setLevel(area.getLevel());
            userArea.setUserId(user.getId());
            return userArea;
        }).collect(Collectors.toList());
        userAreaMapper.insertBatch(userAreas);
    }


    private void saveUserRole(List<Integer> roleIds, User user) {
        if (CollUtil.isNotEmpty(roleIds)) {
            List<UserRole> userRoles = roleIds.stream().map(roleId -> {
                UserRole userRole = new UserRole();
                userRole.setRoleId(roleId);
                userRole.setUserId(user.getId());
                return userRole;
            }).collect(Collectors.toList());
            userRoleMapper.insertBatch(userRoles);
        }
    }

    @Override
    public ApiResult<IPage<UserVo>> getUsers(Page page, UserAo ao) {
        page.addOrder(OrderItem.desc("id"));
        IPage<UserVo> vos = userMapper.selectByPage(page, ao);
        if (vos.getTotal() > 0) {
            vos.getRecords().forEach(vo -> {
                if (StrUtil.isNotEmpty(vo.getAvatar())) {
                    vo.setAvatar(CommonUtil.concatUrl(serverUrl, vo.getAvatar()));
                }
                List<Integer> roleIds = roleMapper.selectRolesByUserId(vo.getId()).stream().map(Role::getId).collect(Collectors.toList());
                vo.setRoleIds(roleIds);
                if (vo.getOrgId() != null) {
                    String orgName = organizationMapper.selectById(vo.getOrgId()).getTitle();
                    vo.setOrgName(orgName);
                }
                List<UserArea> userAreas = userAreaMapper.selectList(Wrappers.<UserArea>query().lambda().eq(UserArea::getUserId, vo.getId()));
                vo.setUserAreas(userAreas);
            });
        }
        return Result.of(vos);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> delById(Integer id) {
        userRoleMapper.delete(Wrappers.<UserRole>query().lambda().eq(UserRole::getUserId, id));
        userAreaMapper.delete(Wrappers.<UserArea>query().lambda().eq(UserArea::getUserId, id));
        userMapper.deleteById(id);
        return Result.ok("删除用户成功");
    }

    @Override
    public User findByUsername(String username) {
        User user = userMapper.selectOne(Wrappers.<User>query().lambda().eq(User::getUsername, username));
        user.setPassword(null);
        user.setDecodePassword(null);
        if (StrUtil.isNotEmpty(user.getAvatar())) {
            user.setAvatar(CommonUtil.concatUrl(serverUrl, user.getAvatar()));
        }
        List<Role> roles = roleMapper.selectRolesByUserId(user.getId());
        user.setRoles(roles);
        if (StrUtil.equals(UserType.SUPER_ADMIN.code(), user.getUserType())) {
            List<Permission> permissions = permissionMapper.selectList(Wrappers.<Permission>query().lambda().eq(Permission::getStatus, SecurityConst.PERMISSION_STATUS_NORMAL).orderByAsc(Permission::getSortOrder));
            user.setPermissions(permissions);
            return user;
        }
        List<Permission> permissions = permissionMapper.selectByRoleIdsAndDistinct(roles.stream().map(BasePojo::getId).collect(Collectors.toList()), SecurityConst.PERMISSION_STATUS_NORMAL);
        user.setPermissions(permissions);
        return user;
    }

    @Override
    public User findUserByUsername(String username) {
        User user = userMapper.selectOne(Wrappers.<User>query().lambda().eq(User::getUsername, username));
        List<Role> roles = roleMapper.selectRolesByUserId(user.getId());
        user.setRoles(roles);
        return user;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> modifyPass(String oldPassword, String newPassword) {
        String username = SecurityUtil.getUser().getUsername();
        User user = userMapper.selectOne(Wrappers.<User>query().lambda().eq(User::getUsername, username));
        if (user == null) {
            return Result.warn("用户不存在");
        }
        if (!StrUtil.equals(oldPassword, user.getDecodePassword())) {
            return Result.warn("原密码不正确");
        }
        String password = new BCryptPasswordEncoder().encode(newPassword);
        user.setDecodePassword(newPassword);
        user.setPassword(password);
        userMapper.updateById(user);
        return Result.ok("修改密码成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> enableOrDisableUser(User user) {
        userMapper.updateById(user);
        if (SecurityConst.USER_STATUS_NORMAL.equals(user.getStatus())) {
            return Result.ok("启用用户成功");
        }
        return Result.ok("禁用用户成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> editUserArea(UserAreaDto dto) {
        userAreaMapper.delete(Wrappers.<UserArea>query().lambda().eq(UserArea::getUserId, dto.getId()));
        User user = new User();
        BeanUtil.copyProperties(dto, user);
        userMapper.updateById(user);
        if (SecurityConst.DATA_TYPE_CUSTOM.equals(dto.getDataType()) && CollUtil.isNotEmpty(dto.getAreas())) {
            saveUserArea(dto.getAreas(), user);
        }
        return Result.ok("分配区域权限成功");
    }

    @Override
    public List<User> getUserList(UserAo ao) {
        return userMapper.getUserList(ao);
    }

}
